package com.genexususa.eo.google.connection;

import com.genexususa.eo.google.data.*;
import com.google.api.ads.adwords.axis.v201406.cm.*;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;

public class BiddingStrategyManager {

    private String _clientId;

    private static final int PAGE_SIZE = 5000;

    public void SetClientId(String clientId) {
        this._clientId = clientId;
    }

    public String GetClientId() {
        return _clientId;
    }

    public void Finalize() {

        SessionController sc = SessionController.getInstance();
        sc.RemoveSession(_clientId);
    }

    public String CreateBiddingStrategy(String xml){
        String result = "";
        try{
            Util util = new Util();
            GA_Result res = new GA_Result();
            ServiceFactory sf = ServiceFactory.getInstance();
            HashMap<String, Long> biddingGxIds = new HashMap<String, Long>();

            try{
                Document doc = util.loadXMLFromString(xml);
                XPathFactory factory = XPathFactory.newInstance();
                XPath xpath = factory.newXPath();
                XPathExpression expr = xpath.compile("//BiddingStrategy");
                Object biddingNodes = expr.evaluate(doc, XPathConstants.NODESET);
                NodeList biddings = (NodeList) biddingNodes;

                if (biddings.getLength() > 0){
                    ArrayList<SharedBiddingStrategy> bscs = new ArrayList<SharedBiddingStrategy>();
                    for (int i = 0; i < biddings.getLength(); i++){
                        Node n = biddings.item(i);
                        NodeList children = n.getChildNodes();
                        String biddingName = "";
                        Long biddingGxId = 0L;
                        GA_ResultItem item = new GA_ResultItem();

                        SharedBiddingStrategy bsc = new SharedBiddingStrategy();
                        for (int j = 0; j < children.getLength(); j++){

                            if (children.item(j).getNodeName().equalsIgnoreCase("Name")){
                                bsc.setName(children.item(j).getTextContent());
                                biddingName = children.item(j).getTextContent();
                                item.BiddingName = biddingName;
                            }
                            if (children.item(j).getNodeName().equalsIgnoreCase("BiddingGxId")){
                                biddingGxId = Long.parseLong(children.item(j).getTextContent());
                                item.BiddingGxId = biddingGxId;
                            }

                            if (children.item(j).getNodeName().equalsIgnoreCase("BiddingScheme")){
                                NodeList childrenScheme = children.item(j).getChildNodes();
                                for (int h = 0; h < childrenScheme.getLength(); h++){
                                    if (childrenScheme.item(h).getNodeName().equalsIgnoreCase("BSEnhancedCPC")){
                                        bsc.setBiddingScheme(new EnhancedCpcBiddingScheme());
                                        bsc.setType(BiddingStrategyType.ENHANCED_CPC);
                                    }

                                    if (childrenScheme.item(h).getNodeName().equalsIgnoreCase("BSTargetSpend")){

                                        TargetSpendBiddingScheme targetSpendScheme = new TargetSpendBiddingScheme();

                                        NodeList childrenTargetSpend = childrenScheme.item(h).getChildNodes();
                                        for (int index = 0; index < childrenTargetSpend.getLength(); index++){
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("BidCeiling")){
                                                targetSpendScheme.setBidCeiling(new Money(null, Long.parseLong(childrenTargetSpend.item(index).getTextContent())));
                                            }
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("SpendTarget")){
                                                targetSpendScheme.setSpendTarget(new Money(null, Long.parseLong(childrenTargetSpend.item(index).getTextContent())));
                                            }
                                        }
                                        bsc.setBiddingScheme(targetSpendScheme);
                                        bsc.setType(BiddingStrategyType.TARGET_SPEND);
                                    }

                                    if (childrenScheme.item(h).getNodeName().equalsIgnoreCase("BSTargetCPA")){

                                        TargetCpaBiddingScheme targetCPAScheme = new TargetCpaBiddingScheme();

                                        NodeList childrenTargetSpend = childrenScheme.item(h).getChildNodes();
                                        for (int index = 0; index < childrenTargetSpend.getLength(); index++){
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("MaxCPCBidCeiling")){
                                                targetCPAScheme.setMaxCpcBidCeiling(new Money(null, Long.parseLong(childrenTargetSpend.item(index).getTextContent())));
                                            }
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("MaxCPCBidFloor")){
                                                targetCPAScheme.setMaxCpcBidFloor(new Money(null, Long.parseLong(childrenTargetSpend.item(index).getTextContent())));
                                            }
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("TargetCPA")){
                                                targetCPAScheme.setTargetCpa(new Money(null, Long.parseLong(childrenTargetSpend.item(index).getTextContent())));
                                            }
                                        }
                                        bsc.setBiddingScheme(targetCPAScheme);
                                        bsc.setType(BiddingStrategyType.TARGET_CPA);
                                    }

                                    if (childrenScheme.item(h).getNodeName().equalsIgnoreCase("BSTargetROAS")){

                                        TargetRoasBiddingScheme targetROASScheme = new TargetRoasBiddingScheme();

                                        NodeList childrenTargetSpend = childrenScheme.item(h).getChildNodes();
                                        for (int index = 0; index < childrenTargetSpend.getLength(); index++){
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("BidCeiling")){
                                                targetROASScheme.setBidCeiling(new Money(null, Long.parseLong(childrenTargetSpend.item(index).getTextContent())));
                                            }
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("BidFloor")){
                                                targetROASScheme.setBidFloor(new Money(null, Long.parseLong(childrenTargetSpend.item(index).getTextContent())));
                                            }
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("TargetROAS")){
                                                targetROASScheme.setTargetRoas(Double.parseDouble(childrenTargetSpend.item(index).getTextContent()));
                                            }
                                        }
                                        bsc.setBiddingScheme(targetROASScheme);
                                        bsc.setType(BiddingStrategyType.TARGET_ROAS);
                                    }

                                    if (childrenScheme.item(h).getNodeName().equalsIgnoreCase("BSBudgetOptimizer")){

                                        BudgetOptimizerBiddingScheme budgetOptimizerScheme = new BudgetOptimizerBiddingScheme();

                                        NodeList childrenTargetSpend = childrenScheme.item(h).getChildNodes();
                                        for (int index = 0; index < childrenTargetSpend.getLength(); index++){
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("BidCeiling")){
                                                budgetOptimizerScheme.setBidCeiling(new Money(null, Long.parseLong(childrenTargetSpend.item(index).getTextContent())));
                                            }
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("EnhancedCPC")){
                                                budgetOptimizerScheme.setEnhancedCpcEnabled(Boolean.parseBoolean(childrenTargetSpend.item(index).getTextContent()));
                                            }
                                        }
                                        bsc.setBiddingScheme(budgetOptimizerScheme);
                                        bsc.setType(BiddingStrategyType.BUDGET_OPTIMIZER);
                                    }

                                    /*if (childrenScheme.item(h).getNodeName().equalsIgnoreCase("BSConversionOptimizer")){

                                        ConversionOptimizerBiddingScheme conversionOptimizerScheme = new ConversionOptimizerBiddingScheme();

                                        NodeList childrenTargetSpend = childrenScheme.item(h).getChildNodes();
                                        for (int index = 0; index < childrenTargetSpend.getLength(); index++){
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("BidCeiling")){
                                                conversionOptimizerScheme.set .setBidCeiling(new Money(null, Long.parseLong(childrenTargetSpend.item(index).getTextContent())));
                                            }
                                            if (childrenTargetSpend.item(index).getNodeName().equalsIgnoreCase("EnhancedCPC")){
                                                budgetOptimizerScheme.setEnhancedCpcEnabled(Boolean.parseBoolean(childrenTargetSpend.item(index).getTextContent()));
                                            }
                                        }
                                        bsc.setBiddingScheme(budgetOptimizerScheme);
                                        bsc.setType(BiddingStrategyType.BUDGET_OPTIMIZER);
                                    }*/


                                }
                            }

                        }
                        bscs.add(bsc);
                        item.BiddingStrategy = bsc;
                        res.Items.add(item);
                        biddingGxIds.put(biddingName, biddingGxId);
                    }

                    ArrayList<GA_ResultItem> created = new ArrayList<GA_ResultItem>();

                    for(GA_ResultItem item : res.Items){

                        BiddingStrategyOperation operation = new BiddingStrategyOperation();
                        operation.setOperand(item.BiddingStrategy);
                        operation.setOperator(Operator.ADD);
                        BiddingStrategyServiceInterface service = sf.GetBiddingStrategyServiceInterface(this._clientId);

                        try{

                            BiddingStrategyOperation[] operations = new BiddingStrategyOperation[] {operation};
                            BiddingStrategyReturnValue returnValue = service.mutate(operations);

                            SharedBiddingStrategy newBiddingStrategy = returnValue.getValue(0);

                            item.BiddingId = newBiddingStrategy.getId();
                            created.add(item);


                        }catch (ApiException apiException){

                            ApiError[] apiErrors = apiException.getErrors();

                            item.BiddingId = 0L;
                            item.HasError = true;

                            for (ApiError apiError : apiErrors) {

                                ErrorsStruct errors = new ErrorsStruct();

                                errors.Message = apiError.getErrorString();

                                errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

                                com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

                                err.ErrorString = apiError.getErrorString();
                                err.fieldPath = apiError.getFieldPath();
                                err.Reason = apiException.getFaultReason();
                                err.Trigger = apiError.getTrigger();
                                err.Type = apiError.getApiErrorType();

                                errors.Errors.add(err);

                                item.Errors = errors;

                                created.add(item);
                            }
                        }


                    }

                    try {

                        JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                        Marshaller marshallerObj = contextObj.createMarshaller();
                        marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                        StringWriter sw = new StringWriter();

                        res.Items = created;

                        marshallerObj.marshal(res, sw);
                        result = sw.getBuffer().toString();
                        System.out.println(result);
                        String s = "";

                    } catch (Exception exc) {
                        exc.printStackTrace();
                        result = exc.getMessage();
                    }


                }


            }catch (Exception e){

            }


        }catch (Exception exc){
            GA_Result res = new GA_Result();

            ArrayList<GA_ResultItem> items = new ArrayList<GA_ResultItem>();

            GA_ResultItem error = new GA_ResultItem();

            ErrorsStruct errors = new ErrorsStruct();

            errors.Message = exc.getMessage();

            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

            StringWriter st = new StringWriter();
            exc.printStackTrace(new PrintWriter(st));

            err.UnknownError = st.toString();

            errors.Errors.add(err);

            error.Errors = errors;

            error.HasError = true;

            items.add(error);

            result = "";

            try {

                JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                StringWriter sw = new StringWriter();

                res.Items = items;

                marshallerObj.marshal(res, sw);
                result = sw.getBuffer().toString();
                System.out.println(result);
                return result;

            } catch (Exception ex) {
                ex.printStackTrace();
                result = ex.getMessage();
                return result;
            }
        }

        return result;



    }

    public ArrayList<GA_SharedBiddingStrategy> GetBiddingStrategies(){
        ArrayList<GA_SharedBiddingStrategy> biddingStrategies = new ArrayList<GA_SharedBiddingStrategy>();
        ServiceFactory sf = ServiceFactory.getInstance();
        try {
            BiddingStrategyServiceInterface service = sf.GetBiddingStrategyServiceInterface(this._clientId);

            int offset = 0;
            Selector selector = new Selector();

            selector.setPaging(new Paging(offset, PAGE_SIZE));

            selector.setFields(new String[]
                    {
                            "Id",
                            "Name",
                            "Status",
                            "Type",
                            "BiddingScheme"
                    });

            BiddingStrategyPage page = null;

            try {
                do {
                    page = service.get(selector);


                    if (page.getEntries() != null) {
                        for (SharedBiddingStrategy bs : page.getEntries()) {
                            GA_SharedBiddingStrategy sharedBiddingStrategy = new GA_SharedBiddingStrategy();
                            sharedBiddingStrategy.Id = bs.getId();
                            sharedBiddingStrategy.Name = bs.getName();
                            sharedBiddingStrategy.BiddingScheme = bs.getBiddingScheme().getBiddingSchemeType();
                            sharedBiddingStrategy.Status = bs.getStatus().getValue();
                            sharedBiddingStrategy.Type = bs.getType().getValue();

                            biddingStrategies.add(sharedBiddingStrategy);

                        }
                    }

                    offset += PAGE_SIZE;
                    selector.getPaging().setStartIndex(offset);
                } while (offset < page.getTotalNumEntries());

            } catch (RemoteException e) {
                e.printStackTrace(System.out);
            }
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }

        return biddingStrategies;


    }

    public String AssociateBiddingStrategyToCampaign(Long campaignId, Long biddingStrategyId) {
        GA_Result result = new GA_Result();
        try {
            ServiceFactory sf = ServiceFactory.getInstance();
            CampaignServiceInterface campaignService = sf.GetCampaignService(this._clientId);


            BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration();
            biddingStrategyConfiguration.setBiddingStrategyId(biddingStrategyId);

            Campaign campaign = new Campaign();
            campaign.setId(campaignId);

            campaign.setBiddingStrategyConfiguration(biddingStrategyConfiguration);

            CampaignOperation operation = new CampaignOperation();
            operation.setOperand(campaign);
            operation.setOperator(Operator.SET);
            CampaignOperation[] operations = new CampaignOperation[]{operation};

            GA_ResultItem item = new GA_ResultItem();
            item.CampaignId = campaignId;
            item.BiddingId = biddingStrategyId;

            try {
                CampaignReturnValue returnValue = campaignService.mutate(operations);

                item.HasError = false;
                result.Items.add(item);

            } catch (ApiException apiException) {

                item.HasError = true;


                ApiError[] apiErrors = apiException.getErrors();

                for (ApiError apiError : apiErrors) {
                    ErrorsStruct errors = new ErrorsStruct();

                    errors.Message = apiError.getErrorString();

                    errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

                    com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

                    err.ErrorString = apiError.getErrorString();
                    err.fieldPath = apiError.getFieldPath();
                    err.Reason = apiException.getFaultReason();
                    err.Trigger = apiError.getTrigger();
                    err.Type = apiError.getApiErrorType();

                    errors.Errors.add(err);

                    item.Errors = errors;


                }
                result.Items.add(item);


            } catch (RemoteException exc) {
                item.HasError = true;

                ErrorsStruct errors = new ErrorsStruct();


                errors.Message = exc.getMessage();

                errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

                com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

                StringWriter st = new StringWriter();
                exc.printStackTrace(new PrintWriter(st));

                err.UnknownError = st.toString();

                errors.Errors.add(err);

                item.Errors = errors;

                item.HasError = true;

                result.Items.add(item);


            } finally {
                try {

                    JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                    Marshaller marshallerObj = contextObj.createMarshaller();
                    marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                    StringWriter sw = new StringWriter();

                    //res.Items = created

                    marshallerObj.marshal(result, sw);
                    String res = sw.getBuffer().toString();
                    System.out.println(result);
                    String s = "";
                    return res;

                } catch (Exception excAux) {

                }
            }
        } catch (Exception exc) {
            GA_ResultItem item = new GA_ResultItem();
            item.HasError = true;

            ErrorsStruct errors = new ErrorsStruct();


            errors.Message = exc.getMessage();

            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

            StringWriter st = new StringWriter();
            exc.printStackTrace(new PrintWriter(st));

            err.UnknownError = st.toString();

            errors.Errors.add(err);

            item.Errors = errors;

            item.HasError = true;

            result.Items.add(item);
        }

        return "";
    }

}
